package com.iwuke.dance.http_request;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import com.google.gson.Gson;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import com.iwuke.dance.R;
import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import com.iwuke.dance.util.LogUtil;

public class OKHttpRequest implements NetRequest {

    static int cacheSize = 10 * 1024 * 1024; // 10 MiB

    private static OkHttpClient client ;
    private Context mContext;

    public static Handler mHandler=new Handler(Looper.getMainLooper());

    public static Handler getHandler(){
        if(mHandler==null){
            mHandler=new Handler(Looper.getMainLooper());
        }
        return mHandler;
    }

    @Override
    public void init(Context context) {
        mContext = context.getApplicationContext();
        client=getCilent();
    }

    private volatile static OKHttpRequest instance = null;

    private OKHttpRequest(){
    }

    public static OKHttpRequest getInstance() {
        if (instance == null) {
            synchronized (OKHttpRequest.class) {
                if (instance == null) {
                    instance = new OKHttpRequest();
                }
            }
        }


        return instance;
    }

    private OkHttpClient getCilent() {
        if(client==null){
            OkHttpClient.Builder mBuilder= new OkHttpClient.Builder().
                    connectTimeout(10, TimeUnit.SECONDS).writeTimeout(10, TimeUnit.SECONDS)
                    .readTimeout(30, TimeUnit.SECONDS)
                    .addInterceptor(new LoggingInterceptor())
                    .cache(new Cache(mContext.getExternalFilesDir("okhttp"),cacheSize));
            client=mBuilder.build();
        }
        return client;

    }

    @Override
    public void doGet(String url,  final IResponseListener iResponseListener) {
        doGet(url,iResponseListener);
    }

    @Override
    public void doGet(String url, NetworkOption networkOption,
                      final   IResponseListener iResponseListener) {
        Request build = new Request.Builder().url(url).build();

        getCilent().newCall(build).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handleError(e, iResponseListener);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                handleResult(response, iResponseListener);
            }
        });
    }


    @Override
    public void doGet(String url, Map<String, String> paramsMap, final IResponseListener iResponseListener) {
        doGet(url,paramsMap,null,iResponseListener);
    }

    @Override
    public void doGet(String url, Map<String, String> mMap, NetworkOption networkOption,
                      final   IResponseListener iResponseListener) {
        // /* //后加的公共参数
        Map<String, String> paramsMap = MapUtil.getMap(mContext,url, mMap);
        //*/
        url= NetUtils.checkUrl(url);
        url = NetUtils.appendUrl(url, paramsMap);
        LogUtil.logD("+++++++++++url", url);
        final NetworkOption option=NetUtils.checkNetworkOption(networkOption,url);
        Request.Builder builder = new Request.Builder().url(url).tag(option.mTag);
        builder=configHeaders(builder,option);

        Request build = builder.build();

        getCilent().newCall(build).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handleError(e, iResponseListener);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                handleResult(response, iResponseListener);
            }
        });
    }

    private void handleResult(Response response, final IResponseListener iResponseListener) throws IOException {
        final  String result = response.body().string();
        if(iResponseListener!=null){
            getHandler().post(new Runnable() {
                @Override
                public void run() {
                    iResponseListener.onResponse(result);
                }
            });

        }
    }

    private void handleError(IOException e, final IResponseListener iResponseListener) {
        if(iResponseListener!=null){
            final HttpException httpException = new HttpException();
            getHandler().post(new Runnable() {
                @Override
                public void run() {
                    httpException.errMsg = mContext.getString(R.string.net_no);
                    iResponseListener.onFail(httpException);
                }
            });

        }
    }

    private Request.Builder configHeaders(Request.Builder builder, NetworkOption option) {
        Map<String, String> headers = option.mHeaders;
        if(headers==null || headers.size()==0){
            return builder;
        }
        Set<Map.Entry<String, String>> entries = headers.entrySet();
        for(Map.Entry<String, String> entry: entries){
            String key = entry.getKey();
            String value = entry.getValue();
            builder.addHeader(key,value);
        }
        return builder;

    }

    @Override
    public void doPost(String url, Map<String, String> paramsMap, final IResponseListener iResponseListener) {
        doPost(url,paramsMap,null,iResponseListener);

    }

    private FormBody.Builder configPushParam(FormBody.Builder builder, Map<String, String> paramsMap) {
        if(paramsMap!=null){
            Set<Map.Entry<String, String>> entries = paramsMap.entrySet();
            for(Map.Entry<String,String> entry:entries ){
                String key = entry.getKey();
                String value = entry.getValue();
                builder.add(key,value);
            }
        }
        return builder;
    }

    @Override
    public void doPost(String url, Map<String, String> mMap, NetworkOption networkOption,
                       final IResponseListener iResponseListener) {
        // /* //后加的公共参数
        Map<String, String> paramsMap = MapUtil.getMap(mContext,url, mMap);
        //*/
        url= NetUtils.checkUrl(url);

        final NetworkOption option=NetUtils.checkNetworkOption(networkOption,url);
        FormBody.Builder builder = new FormBody.Builder();
        builder=configPushParam(builder,paramsMap);
        FormBody formBody = builder.build();

        Request.Builder requestBuilder = new Request.Builder().url(url).post(formBody).tag(option.mTag);
        requestBuilder=configHeaders(requestBuilder,option);
        Request request = requestBuilder.build();
        getCilent().newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handleError(e,iResponseListener);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                handleResult(response,iResponseListener);
            }
        });
    }

    @Override
    public void doPostFile(String url,String file, Map<String, String> paramsMap, List<String> pathList, final IResponseListener iResponseListener) {
        doPostFile(url,file,paramsMap,pathList,null,iResponseListener);

    }
    @Override
    public void doPostFile(String url,String file, Map<String, String> mMap, List<String> pathList, NetworkOption networkOption,
                       final IResponseListener iResponseListener) {

        // form 表单形式上传
        MultipartBody.Builder requestBody = new MultipartBody.Builder();
        requestBody.setType(MultipartBody.FORM);
        //pathList是文件路径对应的列表
        if (null != pathList && pathList.size() > 0) {
            for (int i = 0; i < pathList.size(); i++) {
                File f = new File(pathList.get(i));
                LogUtil.logD("+++++++++++上传图片url",f+"");
                if (f != null) {
                    // MediaType.parse() 里面是上传的文件类型。  //image/jpeg 文件类型  //"*" 不限制文件类型
                    RequestBody body = RequestBody.create(MediaType.parse("*"), f);

                    // 参数分别为， 请求key(参数名称) ，文件名称 ， RequestBody
                    requestBody.addFormDataPart(file, f.getName(), body);
                }
            }
        }

        //后加的公共参数
        Map<String, String> paramsMap = MapUtil.getMap(mContext, url, mMap);
        if (paramsMap != null) {
            for (String key : paramsMap.keySet()) {
                requestBody.addFormDataPart(key, paramsMap.get(key));
            }
        }

        url= NetUtils.checkUrl(url);

        final NetworkOption option=NetUtils.checkNetworkOption(networkOption,url);

        MultipartBody formBody = requestBody.build();

        Request.Builder requestBuilder = new Request.Builder().url(url).post(formBody).tag(option.mTag);
        requestBuilder=configHeaders(requestBuilder,option);
        //创建Request对象
        Request request = requestBuilder.build();
        getCilent().newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handleError(e,iResponseListener);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                handleResult(response,iResponseListener);
            }
        });
    }


    @Override
    public void doPostJson(String url, Map<String,Object> map, final IResponseListener iResponseListener) {
        doPostJson(url,map,null,iResponseListener);

    }


    private String doPostJson(Map<String, Object> paramsMap) {
        if(paramsMap!=null){
            JSONObject jsonObject = new JSONObject();
            try {
                for(String key : paramsMap.keySet()){
                    jsonObject.put(key, paramsMap.get(key));
                }
                String stringJson = jsonObject.toString();
                return stringJson;
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return "";
    }
    public void doPostJson(String url, Map<String,Object> map, NetworkOption networkOption,
                        final IResponseListener iResponseListener){
        MediaType JSON = MediaType.parse("application/json; charset=utf-8");
        Gson gson = new Gson();
        String s = gson.toJson(map);
        LogUtil.logD("+++++++++++s",s + "");
        RequestBody body = RequestBody.create(JSON, s);
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();


        //同步
        getCilent().newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handleError(e,iResponseListener);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                handleResult(response,iResponseListener);
            }
        });
    }



    //专用
    @Override
    public void doPostJson2(String url, String stringJson, final IResponseListener iResponseListener) {
        doPostJson2(url,stringJson,null,iResponseListener);

    }

    //专用
    public void doPostJson2(String url, String stringJson, NetworkOption networkOption,
                           final IResponseListener iResponseListener){
        MediaType JSON = MediaType.parse("application/json; charset=utf-8");

        RequestBody body = RequestBody.create(JSON, stringJson);
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();


        //同步
        getCilent().newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handleError(e,iResponseListener);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                handleResult(response,iResponseListener);
            }
        });
    }

    @Override
    public void doPut(String url, Map<String, String> paramsMap, final IResponseListener iResponseListener) {
        doPut(url,paramsMap,null,iResponseListener);

    }

    @Override
    public void doPut(String url, Map<String, String> mMap, NetworkOption networkOption,
                       final IResponseListener iResponseListener) {
        // /* //后加的公共参数
        Map<String, String> paramsMap = MapUtil.getMap(mContext,url, mMap);
        //*/
        url= NetUtils.checkUrl(url);

        final NetworkOption option=NetUtils.checkNetworkOption(networkOption,url);
        FormBody.Builder builder = new FormBody.Builder();
        builder=configPushParam(builder,paramsMap);
        FormBody formBody = builder.build();

        Request.Builder requestBuilder = new Request.Builder().url(url).put(formBody).tag(option.mTag);
        requestBuilder=configHeaders(requestBuilder,option);
        Request request = requestBuilder.build();
        getCilent().newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handleError(e,iResponseListener);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                handleResult(response,iResponseListener);
            }
        });
    }

    @Override
    public void doPutJson(String url, Map<String,Object> map, final IResponseListener iResponseListener) {
        doPutJson(url,map,null,iResponseListener);

    }

    public void doPutJson(String url, Map<String,Object> map, NetworkOption networkOption,
                           final IResponseListener iResponseListener){
        MediaType JSON = MediaType.parse("application/json; charset=utf-8");
        Gson gson = new Gson();
        String s = gson.toJson(map);
        LogUtil.logD("+++++++++++s",s + "");
        RequestBody body = RequestBody.create(JSON, s);
        Request request = new Request.Builder()
                .url(url)
                .put(body)
                .build();


        //同步
        getCilent().newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handleError(e,iResponseListener);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                handleResult(response,iResponseListener);
            }
        });
    }


    /**
     * @description 图文上传 put类型
     * @param
     */
    @Override
    public void doPutForm(String url, ArrayList<String> pathList, Map<String, String> paramsMap, final IResponseListener iResponseListener) {
        doPutForm(url,pathList,paramsMap,null,iResponseListener);

    }

    @Override
    public void doPutForm(String url, ArrayList<String> pathList, Map<String, String> mMap, NetworkOption networkOption,
                          final IResponseListener iResponseListener) {

        //*/
        url= NetUtils.checkUrl(url);
        final NetworkOption option=NetUtils.checkNetworkOption(networkOption,url);
        // form 表单形式上传
        MultipartBody.Builder requestBody = new MultipartBody.Builder();
        requestBody.setType(MultipartBody.FORM);
        //pathList是文件路径对应的列表
        if (null != pathList && pathList.size() > 0) {
            for (int i = 0; i < pathList.size(); i++) {
                File file = new File(pathList.get(i));
                if (file != null) {
                    // MediaType.parse() 里面是上传的文件类型。
                    RequestBody body = RequestBody.create(MediaType.parse("image/*"), file);

                    // 参数分别为， 请求key ，文件名称 ， RequestBody
                    requestBody.addFormDataPart("image", file.getName(), body);
                }
            }
        }

        // /* //后加的公共参数
        Map<String, String> paramsMap = MapUtil.getMap(mContext,url, mMap);
        if (paramsMap != null) {
            for (String key : paramsMap.keySet()) {
                requestBody.addFormDataPart(key, paramsMap.get(key));
            }
        }
        //创建Request对象
        Request.Builder requestBuilder = new Request.Builder().url(url).put(requestBody.build()).tag(option.mTag);
        requestBuilder=configHeaders(requestBuilder,option);
        Request request = requestBuilder.build();
        getCilent().newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handleError(e,iResponseListener);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                handleResult(response,iResponseListener);
            }
        });
    }

    @Override
    public void doDelete(String url, Map<String, String> paramsMap, final IResponseListener iResponseListener) {
        doDelete(url,paramsMap,null,iResponseListener);

    }

    @Override
    public void doDelete(String url, Map<String, String> mMap, NetworkOption networkOption,
                      final IResponseListener iResponseListener) {
        // /* //后加的公共参数
        Map<String, String> paramsMap = MapUtil.getMap(mContext,url, mMap);
        //*/
        url= NetUtils.checkUrl(url);

        final NetworkOption option=NetUtils.checkNetworkOption(networkOption,url);
        FormBody.Builder builder = new FormBody.Builder();
        builder=configPushParam(builder,paramsMap);
        FormBody formBody = builder.build();

        Log.d("++++++++++delete=",url);
        Request.Builder requestBuilder = new Request.Builder().url(url).delete(formBody).tag(option.mTag);
        requestBuilder=configHeaders(requestBuilder,option);
        Request request = requestBuilder.build();
        getCilent().newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handleError(e,iResponseListener);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                handleResult(response,iResponseListener);
            }
        });
    }


    @Override
    public void doDeleteJson(String url, Map<String, Object> paramsMap, final IResponseListener iResponseListener) {
        doDeleteJson(url,paramsMap,null,iResponseListener);

    }

    @Override
    public void doDeleteJson(String url, Map<String, Object> mMap, NetworkOption networkOption,
                         final IResponseListener iResponseListener) {

        MediaType JSON = MediaType.parse("application/json; charset=utf-8");
        Gson gson = new Gson();
        String s = gson.toJson(mMap);
        RequestBody body = RequestBody.create(JSON, s);
        Request request = new Request.Builder()
                .url(url)
                .delete(body)
                .build();

        getCilent().newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handleError(e,iResponseListener);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                handleResult(response,iResponseListener);
            }
        });
    }


    @Override
    public void cancel(Object tag) {
        if(client!=null){
            if(client != null) {
                for(Call call : client.dispatcher().queuedCalls()) {

                    if(tag!=null&&call.request().tag()!=null){
                        if (call.request().tag().equals(tag))
                            call.cancel();
                    }
                }
                for(Call call : client.dispatcher().runningCalls()) {
                    if(tag!=null&&call.request().tag()!=null){
                        if (call.request().tag().equals(tag))
                            call.cancel();
                    }

                }
            }
        }
    }


}

